#pragma once
#include<iostream>
#include<pthread.h>
#include<vector>
#include<unistd.h>
#include<string>
#include<queue>

template<class T>
class ThreadPool
{
public:
    THreadPool(int num)
    {
        thread_num = num;
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ~ThreadPool()
    {
        pthread_mutex_destory(&mutex);
        pthread_cond_destory(&_cond);
    }

    static void* handler(void* args)
    {
        pthread_detach(pthread_self());
        ThreadPool* self = (ThreadPool*)args;
        while (true)
        {
            self->LockQueue();
            while (self->IsEmpty())
            {
                self->Wait();
            }
            T task;
            self->_taskqueue.Pop(&task);
        }
    }

private:
    int thread_num;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
    std::queue<T> _taskqueue;

    bool IsEmpty()
    {
        return _taskqueuequeue.empty();
    }

    void LockQueue()
    {
        pthread_mutex_lock(&mutex);
    }

    void UnLockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void Wait()
    {
        pthread_cond_wait(&cond, &_mutex);
    }

    void WakeUp()
    {
        pthread_cond_signal(&cond);
    }

    void Push(const T& task)
    {
        LockQueue();
        _taskqueuequeue.push(task);
        UnLockQueue();
    }

    void Pop(T& task)
    {
        task = _taskqueue.front();
        _taskqueue.pop();
    }
};